#include "LogSink.h"

// 检查并创建文件及其路径
std::ofstream mylog::checkAndCreateFile(const std::string& filePath,
                                        std::ios_base::openmode mode) {
    std::filesystem::path path(filePath);
    if (!std::filesystem::exists(path)) {
        try {
            // 创建父目录
            std::filesystem::create_directories(path.parent_path());
        } catch (const std::filesystem::filesystem_error& e) {
            std::cerr << "Error creating file or directories: " << e.what()
                      << std::endl;
        }
    }
    // 创建文件
    std::ofstream file(path, mode);
    return file;
}

void mylog::RollBySizeSink::log(const char* data, size_t len) {
    // 判断文件是否超出大小
    if (_cur_size >= _max_size) createNewFile();
    _ofs.write(data, len);
    _cur_size += len;
}

// 得到要生成的日志文件的名称
// 通过基础文件名 + 时间组成 + 计数器 生成真正的文件名
std::string mylog::RollBySizeSink::GetFileName() {
    std::time_t now = std::time(nullptr);
    char buffer[80];
    std::strftime(buffer, sizeof(buffer), "%Y-%m-%d_%H:%M:%S",
                  std::localtime(&now));
    std::string_view timestamp(buffer);
    std::string filename = _basename;
    filename.append(timestamp);
    filename.append("-");
    filename.append(std::to_string(_name_cout++));
    filename.append(".log");
    return filename;
}

void mylog::RollBySizeSink::createNewFile() {
    if (_ofs.is_open()) _ofs.close();
    
    std::string filename = GetFileName();
    _ofs = checkAndCreateFile(filename, std::ios::binary | std::ios::app);
    if (!_ofs.is_open())
        throw std::runtime_error("Failed to open new file in RollBySizeSink: " +
                                 filename);
    _cur_size = 0;
}

void testLogSink() {
    try {
        auto stdoutSink = mylog::SinkFactory::create<mylog::StdOutSink>();
        stdoutSink->log("This is a log message to stdout", 27);

        auto fileSink =
            mylog::SinkFactory::create<mylog::FileSink>("./logs/test.log");
        for (int i = 0; i < 1000; i++) {
            fileSink->log(
                "This is a log message to file\n",
                std::string("This is a log message to file\n").size());
        }

        auto rollSink = mylog::SinkFactory::create<mylog::RollBySizeSink>(
            "./logs/roll", 1024);
        rollSink->log("This is a log message to rolling file", 31);
    } catch (const std::runtime_error& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }
}